package tree.model;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;

public class TreeNode
{
  private TreeNode parent;

  private TreeNode[] children = new TreeNode[0];

  public TreeNode ()
  {
    // Nothing needed.
  }

  public TreeNode (int userObject)
  {
    m_userData = userObject;
  }

  public void add (TreeNode child, int index)
  {
    // Add the child to the list of children.
    if ( index < 0 || index == children.length )  // then append
    {
      TreeNode[] newChildren = new TreeNode[ children.length + 1 ];
      System.arraycopy( children, 0, newChildren, 0, children.length );
      newChildren[children.length] = child;
      children = newChildren;
    }
    else if ( index > children.length )
    {
      throw new IllegalArgumentException("Cannot add child to index " + index + ".  There are only " + children.length + " children.");
    }
    else  // insert
    {
      TreeNode[] newChildren = new TreeNode[ children.length + 1 ];
      if ( index > 0 )
      {
        System.arraycopy( children, 0, newChildren, 0, index );
      }
      newChildren[index] = child;
      System.arraycopy( children, index, newChildren, index + 1, children.length - index );
      children = newChildren;
    }
    
    // Set the parent of the child.
    child.parent = this;
  }

  public void add (TreeNode child)
  {
    add( child, -1 );
  }

  public TreeNode remove (int index)
  {
    if ( index < 0 || index >= children.length ) throw new IllegalArgumentException("Cannot remove element with index " + index + " when there are " + children.length + " elements.");
    
    // Get a handle to the node being removed.
    TreeNode node = children[index];
    node.parent = null;
    
    // Remove the child from this node.
    TreeNode[] newChildren = new TreeNode[ children.length - 1 ];
    if ( index > 0 )
    {
      System.arraycopy( children, 0, newChildren, 0, index );
    }
    if ( index != children.length - 1 )
    {
      System.arraycopy( children, index + 1, newChildren, index, children.length - index - 1 );
    }
    children = newChildren;
    
    return node;
  }

  public void removeFromParent ()
  {
    if ( parent != null )
    {
      int position = this.index();
      parent.remove( position );
      parent = null;
    }
  }

  public TreeNode getParent ()
  {
    return parent;
  }

  public boolean isRoot ()
  {
    if ( parent == null )
    {
      return true;
    }
    else
    {
      return false;
    }
  }

  public TreeNode[] children ()
  {
    return children;
  }

  public boolean hasChildren ()
  {
    if ( children.length == 0 )
    {
      return false;
    }
    else
    {
      return true;
    }
  }

  public int index ()
  {
    if ( parent != null )
    {
      for ( int i = 0; ; i++ )
      {
        Object node = parent.children[i];
        
        if ( this == node )
        {
          return i;
        }
      }
    }
    // Only ever make it here if this is the root node.
    return -1;
  }

  public int depth ()
  {
    int depth = recurseDepth( parent, 0 );
    return depth;
  }

  private int recurseDepth (TreeNode node, int depth)
  {
    if ( node == null )  // reached top of tree
    {
      return depth;
    }
    else
    {
      return recurseDepth( node.parent, depth + 1 );
    }
  }
  
  /**
   * The full depth
   */  
  public int fullDepth(TreeNode node){
	  if (node.children.length == 0) {
	        return 1;
	  }
	  else{
		  int maxD = 1;
		  for (int i = 0; i<node.children.length; i++){
			  if (maxD < fullDepth(node.children[i])){
				  maxD = fullDepth(node.children[i]);
			  }			  
		  }		  
		  return maxD+1;
	  }
	}
  
  /**
   * The number of nodes at the level
   */  
  public int recursenumberNodeAtLev(TreeNode node, int lev){
	  if (lev == 0) {
	        return node.children.length;
	  }
	  else{
		  int sum = 0;
		  lev = lev - 1;
		  for (int i = 0; i<node.children.length; i++){
			  sum = sum + recursenumberNodeAtLev(node.children[i], lev);
		  }		  
		  return sum;
	  }
	}  
   
  public int numberNodeAtLev(int level){
	  level = level - 1;
	  if (level == 0){
		  return 1;
	  }
	  else{
		  int nN = recursenumberNodeAtLev(this, level-1);
			return nN;	
	  }
	    
  }

  /**
   * The wigth of node's place
   */ 
  public int wigthNodeR(TreeNode node){
	  int w = 0;
	  if(node.children.length > 0){
		  for (int i = 0; i<node.children.length; i++){
			 w = w + wigthNodeR(node.children[i]);
		  }
		  return w;
	  }
	  else{	  
		  return 1;
	  }	  
  }
  
  public int wigthNode(){
	  int w = 0;
	  if(this.children.length > 0){
		  for (int i = 0; i<this.children.length; i++){
				 w = w + wigthNodeR(this.children[i]);
			  }
		  return w;
	  }
	  else{
		  return 1;
	  }
  }

  /**
   * The number of nodes at the level
   */ 
  public List<String> NodesAtLevelR(int lev){
	  List<String> listNode=new ArrayList<String>();
	  if(lev ==1){
		  listNode.add(String.valueOf(this.getUserObject()));		  
	  }
	  else{
		  for (int i = 0; i<this.children.length; i++){
			  listNode.addAll(this.children[i].NodesAtLevelR(lev-1));
			  }
	  }
	return  listNode;
	} 
  
  public List<String> NodesAtLevel(int lev){
	  List<String> listNode=new ArrayList<String>();
	  if(lev == 1){
		  listNode.add(String.valueOf(this.getUserObject()));		  
	  }
	  else{
		  for (int i = 0; i<this.children.length; i++){
			  listNode.addAll(this.children[i].NodesAtLevelR(lev-1));
			  }
	  }
	return  listNode;
	}
  
  public int m_userData;

  public void setUserObject (int userObject)
  {
    m_userData = userObject;
  }

  public int getUserObject ()
  {
    return m_userData;
  }
  
  public TreeNode getNodeById(int id){
	  TreeNode n = new TreeNode();
	  if (this.m_userData ==id){
		  return this;
	  }
	  else{
		  
		  for (int i = 0; i<this.children.length; i++){
			  n = this.children[i].getNodeById(id);
			  }
		  return n;
	  }	  
  }
  /*
  public int wigthOfCol(Request req){
	  int id = Integer.parseInt(req.id);
	  TreeNode n = new TreeNode();
	  n = this.getNodeById(id, this);	  
	return n.wigthNode();
	  
  }
  */

	 @PostConstruct
	public List<TreeNode> setShowChildren(int id){
		 Connection con = null;		 
		  List<TreeNode> listNode=new ArrayList<TreeNode>();
		   TreeNode child = new TreeNode();
		  try {
		   String url = "jdbc:mysql://localhost:3306/dbagatha";
		   con = DriverManager.getConnection(url, "root","12345");
		   Statement st = con.createStatement();		   
		   ResultSet rsChild = st.executeQuery("select id from request where (request.idparent =" + id + ") ");
		   while (rsChild.next()) {
			   listNode.add(child);
			   child.setUserObject(Integer.parseInt(rsChild.getString(1)));			   
		   }
		  } catch (Exception e) {
		   e.printStackTrace();
		   System.out.println("Exception: " + e.getMessage());
		  } finally {
		   try {
		    if (con != null)
		     con.close();
		   } catch (SQLException e) {
		    
		   }
		  }
		return listNode;	
	 }
	 
	 public List<TreeNode> ShowChildren(TreeNode parentNode){	
		 List<TreeNode> childrenList = new ArrayList<TreeNode>();
		 childrenList = setShowChildren(parentNode.getUserObject());
	      while(! childrenList.isEmpty())
	      {
	    	  parentNode.add(childrenList.get(0));
	    	  childrenList.remove(0);
	      }
	      return childrenList;
	 }
  
}
